﻿using ClientInfrastructure.Config;
using Newtonsoft.Json;
using ShareCode.Dto;
using ShareCode.Entity;
using ShareCode.KeyValue;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Reflection;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Web;

namespace ClientDao
{
    public abstract class BaseBaseDal<T> : IBaseDal<T> where T : BaseBaseEntity, new()
    {
        protected string Controller = string.Empty;

        #region  基础部分
        protected static readonly HttpClient Http = new();
        protected void InitHttpClient()
        {
            if (Http.BaseAddress == default)
            {
                Http.BaseAddress = new Uri(MyAppContextModel.Obj.ConfigModel.ApiServer ?? "");

                Http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//.Add("Content-Type ", "application/json");                                                                                       //Http.DefaultRequestHeaders.Add("Content-Encoding ", "UTF-8");
            }

            if (!string.IsNullOrEmpty(MyAppContextModel.Obj.ConfigModel.Token))
            {
                if (Http.DefaultRequestHeaders.Contains("Token"))
                {
                    if (Http.DefaultRequestHeaders.GetValues("Token").First() != MyAppContextModel.Obj.ConfigModel.Token)
                    {
                        Http.DefaultRequestHeaders.Remove("Token");
                        Http.DefaultRequestHeaders.Add("Token", MyAppContextModel.Obj.ConfigModel.Token);
                    }
                }
                else
                {
                    Http.DefaultRequestHeaders.Add("Token", MyAppContextModel.Obj.ConfigModel.Token);
                }
            }
        }

        public string GetUri(string url = "", bool withDoMain = false)
        {
            if (string.IsNullOrEmpty(url))
            {
                url = this.Controller;
            }
            else
            {
                this.Controller = this.Controller.Trim('/');
                url = url.Trim('/');
                url = $"{this.Controller}/{url}";
            }
            url = url.Trim('/');

            if (withDoMain)
            {
                url = $"{(MyAppContextModel.Obj.ConfigModel.ApiServer ?? "").Trim('/')}/{url}";
            }

            return url;
        }
        public string GetUri(object obj, string url = "", bool withDoMain = false)
        {
            url = GetUri(url, withDoMain);
            if (obj == null) return url;

            PropertyInfo[] propertis = obj.GetType().GetProperties();
            StringBuilder sb = new StringBuilder();
            sb.Append(url);
            if (url.IndexOf('?') < 0)
                sb.Append('?');
            else
                sb.Append('&');

            foreach (var p in propertis)
            {
                var v = p.GetValue(obj, null);
                if (v == null)
                    continue;

                sb.Append($"{p.Name}={HttpUtility.UrlEncode(v.ToString())}&");

            }

            return sb.ToString().TrimEnd('&');
        }
        public string GetUri(Dictionary<string, string> kv, string url = "", bool withDoMain = false)
        {
            url = GetUri(url, withDoMain);
            if (kv == null || kv.Count < 1) return url;

            if (string.IsNullOrEmpty(url))
                url = this.Controller;

            StringBuilder sb = new StringBuilder();
            sb.Append(url);
            if (url.IndexOf('?') < 0)
                sb.Append('?');
            else
                sb.Append('&');

            foreach (var p in kv)
            {
                var v = p.Value;
                if (v == null)
                    continue;

                sb.Append($"{p.Key}={HttpUtility.UrlEncode(v.ToString())}&");
            }

            return sb.ToString().TrimEnd('&');
        }
        public string GetUri(object[] kv, string url = "", bool withDoMain = false)
        {
            url = GetUri(url, withDoMain);
            if (kv == null || kv.Length < 1) return url;

            if (string.IsNullOrEmpty(url))
                url = this.Controller;

            StringBuilder sb = new StringBuilder();
            sb.Append(url);

            foreach (var p in kv)
            {

                if (p == null)
                    continue;

                var v = p.ToString();

                if (string.IsNullOrEmpty(v))
                    continue;

                sb.Append($"{v}/");
            }

            return sb.ToString().TrimEnd('/');
        }



        protected async Task<ResultDto<TReturn>> PostAsync<TValue, TReturn>(string requestUri, TValue value) where TValue : class, new()
        {
            requestUri = GetUri(requestUri);

            value ??= new();

            try
            {
                InitHttpClient();
                var theReturn = await Http.PostAsJsonAsync(requestUri, value);

                return await TraslateData<TReturn>(theReturn);
            }
            catch (Exception e)
            {
                return new ResultDto<TReturn>() { Code = 500, Data = default, Message = e.Message };
            }
        }

        protected async Task<ResultDto<TReturn>> GetAsync<TReturn>(string requestUri)
        {
            requestUri = GetUri(requestUri);
            try
            {
                InitHttpClient();
                var theReturn = await Http.PostAsync(requestUri, null);
                return await TraslateData<TReturn>(theReturn);
            }

            catch (Exception e)
            {

                return new ResultDto<TReturn>() { Code = 500, Data = default, Message = e.Message };
            }
        }

        protected async Task<ResultDto<TReturn>> PostAsync<TReturn>(string requestUri)
        {
            requestUri = GetUri(requestUri);
            try
            {
                InitHttpClient();
                var theReturn = await Http.PostAsync(requestUri, null);

                return await TraslateData<TReturn>(theReturn);
            }
            catch (Exception e)
            {

                return new ResultDto<TReturn>() { Code = 500, Data = default, Message = e.Message };
            }
        }

        private async Task<ResultDto<TT>> TraslateData<TT>(HttpResponseMessage response)
        {
            try
            {
                try
                {
                    response.EnsureSuccessStatusCode();
                }
                catch
                {
                    if (response.StatusCode != HttpStatusCode.OK)
                    {//这里表示HTTP错误，但并不是逻辑错误
                        HttpContent c = response.Content;
                        var str = await c.ReadAsStringAsync();

                        var result2 = JsonConvert.DeserializeObject<ResultDto<Object>>(str);

                        if (result2 == null)
                        {
                            return new ResultDto<TT>() { Code = 500, Data = default, Message = "未知错误" };
                        }


                        var result3 = new ResultDto<TT>() { Code = result2.Code, Data = default, DetailMSg = result2.DetailMSg, Message = result2.Message };

                        return result3;
                    }
                }

                {
                    HttpContent c = response.Content;
                    var str = await c.ReadAsStringAsync();

                    //这里就得处理逻辑错误了

                    var result2 = JsonConvert.DeserializeObject<ResultDto<Object>>(str);
                    if (result2 == null)
                    {
                        return new ResultDto<TT>() { Code = 500, Data = default, Message = "未知错误" };
                    }
                    var result3 = new ResultDto<TT>() { Code = result2.Code, Data = default, DetailMSg = result2.DetailMSg, Message = result2.Message };

                    if (result2.Success)
                    {
                        if (result2.Data is TT data)
                        {
                            result3.Data = data;
                        }
                        else if (result2.Data == null)
                        {
                            result3.Data = default;
                        }
                        else
                        {
                            var asdf = result2.Data.ToString();
                            if (string.IsNullOrEmpty(asdf))
                            {
                                result3.Data = default;
                            }
                            else
                            {
                                var result4 = JsonConvert.DeserializeObject<TT>(asdf);
                                result3.Data = result4;
                            }

                        }
                    }

                    return result3;
                }
            }
            catch (Exception e)
            {

                return new ResultDto<TT>() { Code = 500, Data = default, Message = e.Message };
            }
        }

        protected MultipartFormDataContent InitDataContent<TT>(TT value, string pre = "Model")
        {
            var formData = new MultipartFormDataContent();

            InitDataContent(formData, value, pre);

            return formData;
        }
        protected MultipartFormDataContent InitDataContent<TT>(MultipartFormDataContent formData, TT value, string pre = "")
        {
            if (value == null)
            {
                return formData;
            }

            if (!string.IsNullOrEmpty(pre))
            {
                pre += ".";
            }

            var modelType = value.GetType();
            foreach (var item in modelType.GetProperties())
            {
                var itemValue = item.GetValue(value);
                if (itemValue != null)
                {
                    if (itemValue is ICollection itemitem)
                    {
                        foreach (var item2 in itemitem)
                        {
                            if (item2 == default) { continue; }

                            var temp = item2.ToString();
                            if (temp == null) continue;

                            var content2 = new StringContent(temp);
                            formData.Add(content2, pre + item.Name);
                        }
                        continue;
                    }
                    var strItemValue = itemValue.ToString();
                    if (strItemValue != null)
                    {
                        var content = new StringContent(strItemValue);
                        formData.Add(content, pre + item.Name);
                    }
                }
            }

            return formData;
        }

        protected MultipartFormDataContent InitDataContent(MultipartFormDataContent dataContent, string key, string value)
        {
            dataContent.Add(new StringContent(value), key);
            return dataContent;
        }
        protected MultipartFormDataContent InitFileDataContent(MultipartFormDataContent dataContent, string filePath, string fileName = "", string key = "Files")
        {
            if (!System.IO.File.Exists(filePath)) return dataContent;

            if (string.IsNullOrEmpty(fileName))
            {
                fileName = EnumFileUsage.Default.ToString();
            }

            fileName += Path.GetExtension(filePath);

            dataContent.Add(new ByteArrayContent(System.IO.File.ReadAllBytes(filePath)), key, fileName);

            return dataContent;
        }

        protected async Task<Stream> GetStreamAsync(string requestUri)
        {
            requestUri = GetUri(requestUri);

            try
            {
                InitHttpClient();
                var response = await Http.GetAsync(requestUri);

                response.EnsureSuccessStatusCode();

                HttpContent c = response.Content;

                return await c.ReadAsStreamAsync();
            }

            catch
            {

                throw;
            }
        }

        protected async Task<ResultDto<TReturn>> PostFormAsync<TReturn>(string requestUri, HttpContent value)
        {
            requestUri = GetUri(requestUri);

            try
            {
                InitHttpClient();

                var theReturn = await Http.PostAsync(requestUri, value);

                return await TraslateData<TReturn>(theReturn);

            }
            catch (Exception e)
            {

                return new ResultDto<TReturn>() { Code = 500, Data = default, Message = e.Message };
            }
        }

        #endregion

        #region 基础接口

        public async Task<ResultDto<T>> GetEntityAsync(long Id)
        {
            var imgstream = await PostAsync<T>($"GetEntity/{Id}");

            return imgstream;
        }

        public async Task<ResultDto<long>> InsertAsync<TT>(TT entity) where TT : class, new()
        {
            var imgstream = await PostAsync<TT, long>($"Insert", entity);

            return imgstream;
        }
        public async Task<ResultDto<bool>> UpdateAsync<TT>(TT entity) where TT : class, new()
        {
            var imgstream = await PostAsync<TT, bool>($"Updata", entity);

            return imgstream;
        }

        public async Task<ResultDto<bool>> UnLogicDeleteAsync(long Id)
        {
            var imgstream = await PostAsync<bool>($"UnLogicDelete/{Id}");

            return imgstream;
        }
        public async Task<ResultDto<bool>> UnLogicDeleteAsync(List<long> Id)
        {
            var imgstream = await PostAsync<List<long>, bool>($"UnLogicDelete", Id);

            return imgstream;
        }

        public async Task<ResultDto<bool>> LogicDeleteAsync(long Id)
        {
            var imgstream = await PostAsync<bool>($"LogicDelete/{Id}");

            return imgstream;
        }
        public async Task<ResultDto<bool>> LogicDeleteAsync(List<long> Id)
        {
            var imgstream = await PostAsync<List<long>, bool>($"LogicDelete", Id);

            return imgstream;
        }

        public async Task<ResultDto<bool>> UpdateState(long Id, int state)
        {
            var imgstream = await PostAsync<bool>($"UpdateState/{Id}/{state}");

            return imgstream;
        }
        public async Task<ResultDto<bool>> UpdateState(List<long> Id, int state)
        {
            var imgstream = await PostAsync<List<long>, bool>($"UpdateState/{state}", Id);

            return imgstream;
        }

        public async Task<ResultDto<PagingWithDataModel<TT>>> ListPageAsync<TT>(PagingDto SearchModel)
        {

            if (SearchModel == default)
            {
                SearchModel = new PagingDto();
            }

            var imgstream = await PostAsync<PagingDto, PagingWithDataModel<TT>>($"ListPage", SearchModel);

            return imgstream;

        }
        public async Task<ResultDto<List<TT>>> ListAsync<TT>(PagingDto SearchModel)
        {

            if (SearchModel == default)
            {
                SearchModel = new PagingDto();
            }

            var imgstream = await PostAsync<PagingDto, List<TT>>($"List", SearchModel);

            return imgstream;

        }

        public async Task<ResultDto<PagingWithDataModel<TT>>> ListPageNoDeleteAsync<TT>(PagingDto SearchModel)
        {

            if (SearchModel == default)
            {
                SearchModel = new PagingDto();
            }

            var imgstream = await PostAsync<PagingDto, PagingWithDataModel<TT>>($"ListPageNoDelete", SearchModel);

            return imgstream;

        }
        public async Task<ResultDto<List<TT>>> ListNoDeleteAsync<TT>(PagingDto SearchModel)
        {

            if (SearchModel == default)
            {
                SearchModel = new PagingDto();
            }

            var imgstream = await PostAsync<PagingDto, List<TT>>($"ListNoDelete", SearchModel);

            return imgstream;

        }
        #endregion
    }
}
